#include <wchar.h>
#include <stdlib.h>
#include <iostream>
#include <stdio.h>
#include "semanticValidationStructures.h"
#include "semanticCube.h"


using namespace std;

classDirectory classDir;
queue<const wchar_t*> *parametersTypes;
variablesTable *varTable;
procedureDirectory *nuevoEjemplo;

void metodo2() {
	procedureDirectory *directorio = classDir.getElement(L"class").procDir;
	variablesTable *var1 = directorio->getElement(L"global").varTable;
	var1->insertVariable(L"uno", L"int", L"public");
	queue<const wchar_t*> *params = directorio->getElement(L"global").parametersTypes;
	params->enqueue(L"int");
	procedureDirectory *procDir = new procedureDirectory::procedureDirectory();
	classDir.insertClass(L"temp", L"nadie", *procDir);
	procDir->insertProcedure(L"temp", L"public", true, L"int", *parametersTypes, L"type", *varTable);
}

void metodo1() {
	procedureDirectory *procDir = new procedureDirectory::procedureDirectory();

	parametersTypes = new queue<const wchar_t*>;
	varTable = new variablesTable::variablesTable();
	procDir->insertProcedure(L"global", L"public", true, L"int", *parametersTypes, L"type", *varTable); //insertamos el primer procedimiento

	classDir.insertClass(L"class", L"papa", *procDir); //label INSERT_DIR

	procDir->insertProcedure(L"local", L"public", true, L"int", *parametersTypes, L"type", *varTable); //insertamos el segundo procedimiento
	metodo2();
}


int main() {
	classDir = classDirectory::classDirectory();
	metodo1(); //el ATG esta basado en procedimientos
	
	if (classDir.getElement(L"class").id != L"") { //Esta verificacion se hace con classDirs y procDirs SIEMPRE
		procedureDirectory *prueba = classDir.getElement(L"class").procDir;

		if (prueba->exist(L"global")) {
			cout << "Encontro una tupla insertada antes de INSERT_DIR\n";
		}
		if (prueba->exist(L"local")) {
			cout << "Encontro una tupla insertada despues de INSERT_DIR\n";
		}
		if(prueba->exist(L"temp")) {
			cout << "FAIL!\n";
		} 

		variablesTable *variables = prueba->getElement(L"global").varTable;
		if(variables->exist(L"uno")) {
			cout<< "La variable UNO existe!\n";
		}

		queue<const wchar_t*> *params = prueba->getElement(L"global").parametersTypes;
		if(params->front() == L"int") {
			cout<< "El primer parametro es entero! \n";
		}
	} else {
		cout << "No se encontro la clase CLASS\n";
	}

	if (classDir.getElement(L"temp").id != L"") { //Esta verificacion se hace con classDirs y procDirs SIEMPRE
		procedureDirectory *segunda = classDir.getElement(L"temp").procDir;

		if(segunda->exist(L"temp")) {
			cout << "SUCCESS!\n";
		}
	}

	classDir.display();
	cout<< "\n\n";

	classDir.getElement(L"class").procDir->insertIntoDir(classDir.getElement(L"temp").procDir);
	classDir.display();
	cout<< "\n\n";

	procedureDirectory *papa = classDir.getElement(L"temp").procDir;
	variablesTable *mama = papa->getElement(L"global").varTable;
	mama->insertVariable(L"dos", L"int", L"public");
	classDir.display();

	cout << "\nOtra prueba:\n";
	nuevoEjemplo = papa;
	nuevoEjemplo->displayDir();
	cout << "\n\n";
	nuevoEjemplo = classDir.getElement(L"class").procDir;
	nuevoEjemplo->displayDir();
//	delete procDir;
	delete varTable;
	delete parametersTypes;
	
	//Pruebas para memoria
	memory *globalMemory;
	globalMemory = new memory::memory(10000);
	int a=1, direccion;
	float b=2;
	bool c=true;
	char d='a';
	direccion = globalMemory->nextFreeLocation("int");
	globalMemory->insert(a);
	cout << globalMemory->readIntValue(direccion);
	direccion = globalMemory->nextFreeLocation("float");
	globalMemory->insert(b);
	cout << globalMemory->readFloatValue(direccion);
	direccion = globalMemory->nextFreeLocation("bool");
	globalMemory->insert(c);
	cout << globalMemory->readBoolValue(direccion);
	direccion = globalMemory->nextFreeLocation("char");
	globalMemory->insert(d);
	cout << globalMemory->readCharValue(direccion) << "\n";


	semanticCube cubo = semanticCube::semanticCube();
	const wchar_t* t1 = L"boolet";
	const wchar_t* t2 = L"boolet";
	wcout << cubo.ask(t1,L":>",t2) << L"\n";

	delete globalMemory;
	
	//Pruebas para tabla de constantes
	constVariableTable *constantTable;
	constantTable = new constVariableTable::constVariableTable(60000);
	int w=700;
	float v=3.4;
	bool z=true;
	char x='c';
	constantTable->insert(w,"int");
	constantTable->insert(v,"float");
	constantTable->insert(z,"bool");
	constantTable->insert(x,"char");
	cout << constantTable->returnInt(60000) << constantTable->returnFloat(60001) << constantTable->returnBool(60002) << constantTable->returnChar(60003) << "\n";

	int entero = (int)(wcstof(L"12"));
	return 0;
}
